<?php
/***********************************************************************
 * @package    	IvanEngine
 * @subpackage 	Core
 * @author     	Ivan <ivanzx@msn.com>
 * @created    	2010-05-19
 ***********************************************************************/
if(defined("IVANENGINE_CORE_VALIDATOR_TIME"))
	die("Redefinition macro in :".__FILE__."(".__LINE__.")");
define("IVANENGINE_CORE_VALIDATOR_TIME", true);

require_once (dirname(__FILE__).'/ValidatorBase.php');
require_once (dirname(__FILE__).'/../Time.php');

class CValidatorTime extends CValidatorBase
{
	const NM_BadFormat		= 'NM_BadFormat';
	const NO_TimeFormat		= 'NO_TimeFormat';
	const NO_TimeOutput		= 'NO_TimeOutput';
	const NO_TimeFormatError= 'NO_TimeFormatError';
	protected function Initialize($options = array(), $messages = array())
  	{
  		parent::Initialize($options, $messages);

  		$this->AddMessage(self::NM_BadFormat, '"%value%" does not match the time format (%time_format%).');

	    $this->AddOption(self::NO_TimeFormat, null);
	    $this->AddOption(self::NO_TimeOutput, 'H:i:s');
	    $this->AddOption(self::NO_TimeFormatError);
  	}
  	
	protected function DoVerify($value) 
	{
		$regex	= $this->GetOption(self::NO_TimeFormat);
		if (is_array($value))
	    {
	      	$clean = $this->ConvertTimeArrayToTimestamp($value);
	    }
	    else if ($regex)
	    {
	      	if (!preg_match($regex, $value, $match))
	      	{
	        	throw new CExceptionValidator($this, self::NM_BadFormat, array('value' => $value, 
	        		self::NO_TimeFormat => $this->GetOption(self::NO_TimeFormatError) ? 
	        			$this->GetOption(self::NO_TimeFormatError) : 
	        			$this->GetOption(self::NO_TimeFormat)));
	      	}
	
	      $clean = $this->ConvertTimeArrayToTimestamp($match);
	    }
	    else if (!ctype_digit($value))
	    {
	      	$clean = strtotime($value);
	      	if (false === $clean)
	      	{
	        	throw new CExceptionValidator($this, self::NM_Invalid, array('value' => $value));
	      	}
	    }
	    else
	    {
	      	$clean = (integer) $value;
	    }
	
	    return $clean === $this->GetEmptyValue() ? $clean : CTime::Date($this->GetOption(self::NO_TimeOutput), $clean);
	}
	
	protected function ConvertTimeArrayToTimestamp($value)
  	{
	    // all elements must be empty or a number
	    foreach (array('hour', 'minute', 'second') as $key)
	    {
	      	if (isset($value[$key]) && !preg_match('#^\d+$#', $value[$key]) && !empty($value[$key]))
	      	{
	        	throw new CExceptionValidator($this, self::NM_Invalid, array('value' => $value));
	      	}
	    }
	
	    // if second is set, minute and hour must be set
	    // if minute is set, hour must be set
	    if (
	      $this->IsValueSet($value, 'second') && (!$this->IsValueSet($value, 'minute') || !$this->IsValueSet($value, 'hour'))
	      ||
	      $this->IsValueSet($value, 'minute') && !$this->IsValueSet($value, 'hour')
	    )
	    {
	      throw new CExceptionValidator($this, self::NM_Invalid, array('value' => $value));
	    }
	
	    $clean = CTime::MakeTime(
	      isset($value['hour']) ? intval($value['hour']) : 0,
	      isset($value['minute']) ? intval($value['minute']) : 0,
	      isset($value['second']) ? intval($value['second']) : 0
	    );
	
	    if (false === $clean)
	    {
	      	throw new CExceptionValidator($this, self::NM_Invalid, array('value' => var_export($value, true)));
	    }
	
	    return $clean;
  	}

  	protected function IsValueSet($values, $key)
  	{
    	return isset($values[$key]) && !in_array($values[$key], array(null, ''), true);
  	}

 	protected function IsEmpty($value)
  	{
	    if (is_array($value))
	    {
	      	// array is not empty when a value is found
	      	foreach($value as $key => $val)
	      	{
	        	// int and string '0' are 'empty' values that are explicitly accepted
	        	if ($val === 0 || $val === '0' || !empty($val)) return false;
	      	}
	      	return true;
	    }
	
	    return parent::IsEmpty($value);
  	}
}
?>